package com.kamistoat.meimeichat.meimeichatserverapplication.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.net.InetSocketAddress;
import java.util.concurrent.Callable;

/**
 * Netty服务端代码。最终将会由spring拉起。所以这里并没有显式的启动
 * 实现了 Callable<> 接口，目的是之后将整个NettyServer纳入线程池管理。
 * 当NettyServer在线程池中时，如何判断NettyServer的动作执行完毕?就是通过ChannelFuture
 */
@Service("nettyServer")
public class NettyServer implements Callable<ChannelFuture> {

    private final Logger logger = LoggerFactory.getLogger(NettyServer.class);

    // 正常程序，定义两个 LoopGroup，为确保性能将BossGroup的容量设置为2
    private final NioEventLoopGroup bossGroup = new NioEventLoopGroup(8);
    private final NioEventLoopGroup workGroup = new NioEventLoopGroup();
    // 额外定义的 ChannelFuture 变量，用于记录 serverBootstrap.bind() 返回的异步操作句柄，用以检测异步操作是否执行完毕/成功
    private ChannelFuture channelFuture;

    @Value("${netty.ip}")
    private String IP;
    @Value("${netty.port}")
    private Integer PORT;

    @Autowired
    NettyServerChannelInitializer nettyServerChannelInitializer;

    @Override
    public ChannelFuture call() {
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap
                    // 指定LoopGroup
                    .group(this.bossGroup, this.workGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 128)
                    // 指定ChannelInitializer，用于绑定 Handler
                    .childHandler(nettyServerChannelInitializer);
            // netty的bind()库方法自动异步执行，记录其异步操作句柄，用以检测异步操作是否执行完毕/成功
            this.channelFuture = serverBootstrap.bind(new InetSocketAddress(PORT)).syncUninterruptibly();
            // 不再像之前那样监听channel的关闭动作了，而是额外写一个 destroy()方法
            // channelFuture.channel().closeFuture().sync();
        }catch (Exception exception){
            logger.error("Netty Server Start Error: " + exception.getMessage());
        }finally {
            if(this.channelFuture != null && this.channelFuture.isSuccess()){
                logger.info("Netty Server Start Success");
            }else{
                destroy();
                logger.error("Netty Server Closed");
            }
        }
        // 将bind()的异步操作句柄返回
        return this.channelFuture;
    }

    /**
     * 发生异常时，优雅关闭两个LoopGroup
     */
    public void destroy(){
        this.bossGroup.shutdownGracefully();
        this.workGroup.shutdownGracefully();
    }

    /**
     * 用于外部获取 bind() 的异步操作句柄
     * @return
     */
    public ChannelFuture channelFuture(){
        return this.channelFuture;
    }
}
